home *** CD-ROM | disk | FTP | other *** search
/ Clickx 75 / Clickx 75.iso / software / printtools / therasterbatorv12 / source / Rasterbator.cs < prev    next >
Encoding:
Text File  |  2010-01-01  |  10.1 KB  |  348 lines

  1.  
  2. // The Rasterbator Standalone Version 1.0
  3. // Copyright (C) 2004-2005 Matias ─rje
  4. // 
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the GNU General Public License
  7. // as published by the Free Software Foundation; either version 2
  8. // of the License, or (at your option) any later version.
  9. // 
  10. // This program is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. // GNU General Public License for more details.
  14. // 
  15. // You should have received a copy of the GNU General Public License
  16. // along with this program; if not, write to the Free Software
  17. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. using System;
  20. using System.Drawing;
  21. using System.Drawing.Imaging;
  22. using System.Drawing.Drawing2D;
  23. using System.Threading;
  24. using System.Collections.Specialized;
  25. using System.IO;
  26. using iTextSharp.text;
  27. using iTextSharp.text.pdf;
  28.  
  29. using Dr=System.Drawing;
  30.  
  31. namespace Rasterbator {
  32.  
  33.     /// <summary>
  34.     /// Description of Rasterbator.
  35.     /// </summary>
  36.   public class Rasterbator {
  37.   
  38.   NameValueCollection Attr=null;
  39.   
  40.   public Thread Worker=null;
  41.   
  42.   private DateTime LastPing=DateTime.Now;
  43.   
  44.   static readonly TimeSpan TimeoutSpan=TimeSpan.FromSeconds(45);
  45.  
  46.   /// <summary>
  47.   /// Determines whether the Rasterbator has timed out.
  48.   /// </summary>
  49.   /// <remarks>
  50.   /// Used in the web version.
  51.   /// </remarks>
  52.   public bool Timeout {
  53.     get {
  54.       return DateTime.Now.Subtract(LastPing)>TimeoutSpan;
  55.     }
  56.   }
  57.   
  58.   /// <summary>
  59.   /// Pings the Rasterbator
  60.   /// </summary>
  61.   /// <remarks>
  62.   /// Used in the web version.
  63.   /// </remarks>
  64.   public void Ping() {
  65.     LastPing=DateTime.Now;
  66.   }
  67.   
  68.   int Resolution=144;
  69.   
  70.   // paper size in mm
  71.   int PaperWidth, PaperHeight;
  72.   
  73.   // amount of squares in one page
  74.   int SquaresX, SquaresY;
  75.   
  76.   // paper size in pixels
  77.   int PaperSizeX, PaperSizeY;
  78.   
  79.   // paper is divided into squares, circle centers will be placed at square centers
  80.   float SquareSize;
  81.   
  82.   // Area of the original image to utilize
  83.   int x1, x2, y1, y2;
  84.   
  85.   // source area in pixels
  86.   int AreaWidth, AreaHeight;
  87.   
  88.   // output image width in pixels
  89.   int ImageWidth, ImageHeight;
  90.   
  91.   float MaxRadius;
  92.   
  93.   // paper size in dots (pdfwriter units)
  94.   float psx, psy;
  95.   
  96.   // output color
  97.   int R, G, B;
  98.   
  99.   bool UseAverageColor=false;
  100. //  iTextSharp.text.Color OutputColor=null;
  101.   
  102.   Bitmap Source;
  103.   BitmapData SourceData;
  104.   bool OptimizeGetPixel=false;
  105.   
  106.   bool CroppingRectangle;
  107.   
  108.   int TotalPages=0, PagesDone=0;
  109.   
  110.   Document D;
  111.   PdfWriter P;
  112.   PdfContentByte C;
  113.   
  114.   public string ErrorMessage="";
  115.     
  116.   
  117.   string Directory {
  118.     get { return (string)Attr["WorkDirectory"]; }
  119.   }
  120.   
  121.   public Rasterbator(NameValueCollection S) {
  122.     Attr=S;
  123.   }
  124.   
  125.   public void Go() {
  126.     try {
  127.       CreateImage();
  128.     } catch(Exception E) {
  129.       ErrorMessage=E.Message+" "+E.StackTrace;
  130.     }
  131.   }
  132.   
  133.   public void CreateImage() {
  134.   
  135.     ImageWidth=(int)(Convert.ToInt32(Attr["ImageWidth"])/25.4*Resolution);
  136.     ImageHeight=(int)(Convert.ToInt32(Attr["ImageHeight"])/25.4*Resolution);
  137.       
  138.     PaperWidth=Convert.ToInt32(Attr["PaperWidth"]);
  139.     PaperHeight=Convert.ToInt32(Attr["PaperHeight"]);
  140.   
  141.   // paper size in pixels
  142.     PaperSizeX=(int)(PaperWidth/25.4*Resolution);
  143.     PaperSizeY=(int)(PaperHeight/25.4*Resolution);
  144.   
  145.     MaxRadius=(float)Convert.ToDecimal(Attr["RasterSize"])/25.4f*Resolution/2f;
  146.   
  147.     CroppingRectangle=Convert.ToBoolean(Attr["CroppingRectangle"]);
  148.   
  149.     string oc=(string)Attr["RasterColor"];
  150.     if(oc=="avg") {
  151.       UseAverageColor=true;
  152.     } else {
  153.       R=int.Parse(oc.Substring(0,2), System.Globalization.NumberStyles.HexNumber);
  154.       G=int.Parse(oc.Substring(2,2), System.Globalization.NumberStyles.HexNumber);
  155.       B=int.Parse(oc.Substring(4,2), System.Globalization.NumberStyles.HexNumber);
  156.     }
  157.   
  158.     double XAspect=Convert.ToDouble(Attr["OriginalImageWidth"])/Convert.ToDouble(Attr["DisplayImageWidth"]);
  159.     double YAspect=Convert.ToDouble(Attr["OriginalImageHeight"])/Convert.ToDouble(Attr["DisplayImageHeight"]);
  160.   
  161.   // Area of the original image to utilize
  162.     x1=(int)(Convert.ToDouble(Attr["x1"])*XAspect);
  163.     x2=(int)(Convert.ToDouble(Attr["x2"])*XAspect);
  164.     y1=(int)(Convert.ToDouble(Attr["y1"])*YAspect);
  165.     y2=(int)(Convert.ToDouble(Attr["y2"])*YAspect);
  166.   
  167.     AreaWidth=x2-x1;
  168.     AreaHeight=y2-y1;
  169.    
  170.     Source=new Bitmap((string)Attr["OriginalFilename"]);
  171.   
  172.     int PagesX=(int)Math.Ceiling(Convert.ToDouble(Attr["ImageWidth"])/Convert.ToDouble(Attr["PaperWidth"]));
  173.     int PagesY=(int)Math.Ceiling(Convert.ToDouble(Attr["ImageHeight"])/Convert.ToDouble(Attr["PaperHeight"]));
  174.   
  175.   
  176.   // paper is divided into squares, circle centers will be placed at square centers
  177.     SquareSize=(float)(2f*((float)MaxRadius-1f)/Math.Sqrt(2f));
  178.   
  179.   // amount of squares in one page
  180.     SquaresX=(int)(PaperSizeX/SquareSize);
  181.     SquaresY=(int)(PaperSizeY/SquareSize);
  182.   
  183.     psx=72f*(float)PaperWidth/25.4f;
  184.     psy=72f*(float)PaperHeight/25.4f;
  185.   
  186.     D=new Document(new iTextSharp.text.Rectangle(psx, psy), 0, 0, 0, 0);
  187.     P=PdfWriter.getInstance(D, new FileStream(Attr["TargetFilename"].ToString(), FileMode.Create));
  188.     P.setViewerPreferences(PdfWriter.FitWindow);
  189.     D.addTitle("Rasterbation");
  190.     D.addCreator("The Rasterbator at http://homokaasu.org/rasterbator/");
  191.     D.Open();
  192.   
  193.     C=P.DirectContent;
  194.   
  195.     TotalPages=PagesX*PagesY;
  196.     
  197.     // if the pixel format is easy to read directly from bitmap data, use the optimized method
  198.     if(Source.PixelFormat==PixelFormat.Format32bppArgb || Source.PixelFormat==PixelFormat.Format24bppRgb) OptimizeGetPixel=true;
  199.     
  200.     if(OptimizeGetPixel) 
  201.       SourceData=Source.LockBits(new Dr.Rectangle(0, 0, Source.Width, Source.Height), ImageLockMode.ReadOnly, Source.PixelFormat);
  202.   
  203.     PagesDone=0;
  204.     for(int py=0;py<PagesY;py++) for(int px=0;px<PagesX;px++) {
  205.       RasterbatePage(px, py);
  206.       PagesDone++;
  207.     }
  208.     if(OptimizeGetPixel) Source.UnlockBits(SourceData);
  209.  
  210.     D.Close();
  211.     Source.Dispose();
  212.   }
  213.   
  214.   public double Progress {
  215.     get {
  216.       if(TotalPages==0) return 0;
  217.       return (double)PagesDone/(double)TotalPages;
  218.     }
  219.   }
  220.  
  221.   // optimized but unsafe and very fast get pixel for common pixel formats
  222.   private unsafe Dr.Color GetSourcePixel(int x, int y) {
  223.     byte* bp=(byte*)SourceData.Scan0;
  224.     switch(SourceData.PixelFormat) {
  225.       case PixelFormat.Format32bppArgb :
  226.         bp+=(x*4)+(y*SourceData.Stride);
  227.         return Dr.Color.FromArgb(*(bp+3), *(bp+2), *(bp+1), *bp);
  228.       case PixelFormat.Format24bppRgb :
  229.         bp+=(x*3)+(y*SourceData.Stride);
  230.         return Dr.Color.FromArgb(*(bp+2), *(bp+1), *bp);
  231.     }
  232.     return Dr.Color.Empty;
  233.   }
  234.   
  235.   private void RasterbatePage(int px, int py) {
  236.   
  237.     if(!UseAverageColor) C.setRGBColorFill(R, G, B);
  238.   
  239.     // loops every square of the page
  240.   
  241.     float MaxX=float.MinValue;
  242.     float MaxY=float.MinValue;
  243.     
  244.     int pxs=PaperSizeX*px;
  245.     int pys=PaperSizeY*py;
  246.     float awr=(float)AreaWidth/(float)ImageWidth; // area width ratio
  247.     float ahr=(float)AreaHeight/(float)ImageHeight; // area height ratio
  248.   
  249.     // from -1 to +1 since large circles in adjoining pages may partially be visible in this page also.
  250.     for(int sy=-1;sy<SquaresY+1;sy++) {
  251.       
  252.       // this square top pixel in aggregate coordinates of all papers
  253.       int ThisSquareY=(int)(pys+sy*SquareSize);
  254.       
  255.       // square mapped to source image:
  256.       int sy1=(int)(y1+ThisSquareY*ahr);
  257.       if(sy1>=y2) break; // out of boundary - skip remainder column
  258.       int sy2=(int)(y1+(ThisSquareY+SquareSize)*ahr);
  259.             
  260.       for(int sx=-1;sx<SquaresX+1;sx++) {
  261.   
  262.         // this square left pixel in aggregate coordinates of all papers
  263.         int ThisSquareX=(int)(pxs+sx*SquareSize);
  264.   
  265.         // square mapped to source image:
  266.         int sx1=(int)(x1+ThisSquareX*awr);
  267.         if(sx1>=x2) break; // out of boundary - skip remainder row
  268.         int sx2=(int)(x1+(ThisSquareX+SquareSize)*awr);
  269.   
  270.   
  271.         // calculates average brightness
  272.         float Brightness=0;
  273.         float c=0;
  274.         float coc=0;
  275.         float r=0, g=0, b=0;
  276.         for(int by=sy1;by<=sy2;by++) for(int bx=sx1;bx<=sx2;bx++) {
  277.           c++;
  278.           if(bx>=Source.Width || by>=Source.Height || bx>x2 || by>y2 || bx<0 || by<0) {
  279.             Brightness+=1;
  280.             continue;
  281.           }
  282.           
  283.           Dr.Color P=OptimizeGetPixel ? GetSourcePixel(bx, by) : Source.GetPixel(bx, by);
  284.           Brightness+=P.GetBrightness();
  285.           if(!UseAverageColor) continue;
  286.           
  287.           coc++;
  288.           r+=P.R;
  289.           g+=P.G;
  290.           b+=P.B;
  291.         }
  292.   
  293.         float Radius=(1-Brightness/c)*MaxRadius;
  294.   
  295.         float ex=(sx+0.5f)*SquareSize/2f;
  296.         float ey=(sy+0.5f)*SquareSize/2f;
  297.   
  298.         if(UseAverageColor) C.setRGBColorFill((int)(r/coc), (int)(g/coc), (int)(b/coc));
  299.   
  300.         C.circle(ex, psy-ey, Radius/2);
  301.   
  302.         ex+=SquareSize/4;
  303.         ey+=SquareSize/4;
  304.   
  305.         if(ex>MaxX) MaxX=ex;
  306.         if(ey>MaxY) MaxY=ey;
  307.   
  308.         C.fill();
  309.       }
  310.     }
  311.   
  312.     float rx=SquaresX*SquareSize/2;
  313.     float ry=SquaresY*SquareSize/2;
  314.   
  315.     if(MaxX<rx) rx=MaxX;
  316.     if(MaxY<ry) ry=MaxY;
  317.   
  318.     // remove bleed
  319.     C.setRGBColorFill(255, 255, 255);
  320.     C.rectangle(-SquareSize, 0, psx+SquareSize, -SquareSize); // top
  321.     C.fill();
  322.     C.rectangle(-SquareSize, -SquareSize, 0, SquareSize); // left
  323.     C.fill();
  324.     C.rectangle(rx, -SquareSize, SquareSize, psy+SquareSize); // right
  325.     C.fill();
  326.     C.rectangle(-SquareSize, psy-ry, psx+SquareSize, -SquareSize); // bottom
  327.     C.fill();
  328.   
  329.     if(CroppingRectangle) {
  330.       C.LineWidth=0.5f;
  331.       C.moveTo(0, psy);
  332.   
  333.       C.setRGBColorStroke(0xbb, 0xbb, 0xbb);
  334.   
  335.       C.lineTo(rx, psy);
  336.       C.lineTo(rx, psy-ry);
  337.       C.lineTo(0, psy-ry);
  338.       C.lineTo(0, psy);
  339.   
  340.       C.stroke();
  341.     }
  342.   
  343.     D.newPage();
  344.   }
  345.   
  346.   }
  347. }
  348.